﻿using LitJson;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class ShipUIMovePoleData : ShipUIData
{
    public int m_BindKeyForward = 0;
    public int m_BindKeyBack = 0;
    public int m_BindKeyLeft = 0;
    public int m_BindKeyRight = 0;

    public override JsonData Save()
    {
        JsonData root = base.Save();
        root["BindKeyForward"] = m_BindKeyForward;
        root["BindKeyBack"] = m_BindKeyBack;
        root["BindKeyLeft"] = m_BindKeyLeft;
        root["BindKeyRight"] = m_BindKeyRight;
        return root;
    }
    public override bool Load(JsonData root)
    {
        if (!base.Load(root))
            return false;
        IDictionary<string, JsonData> rootObj = root.ValueAsObject();

        if (rootObj.ContainsKey("BindKeyForward"))
            m_BindKeyForward = rootObj["BindKeyForward"].ValueAsInt();
        if (rootObj.ContainsKey("BindKeyBack"))
            m_BindKeyBack = rootObj["BindKeyBack"].ValueAsInt();
        if (rootObj.ContainsKey("BindKeyLeft"))
            m_BindKeyLeft = rootObj["BindKeyLeft"].ValueAsInt();
        if (rootObj.ContainsKey("BindKeyRight"))
            m_BindKeyRight = rootObj["BindKeyRight"].ValueAsInt();
        return true;
    }
}
public class ShipUIMovePole: ShipUI
{
    public delegate OperationType CallbackOprate(Vector3 value, int souce);
    public enum OperationType
    {
        NONE,
        Forward,
        Back,
        Left,
        Right,
        OprationTypeEnd
    }
    public int bindKeyForward
    {
        get { 
            var shipData = m_ShipUIData as ShipUIMovePoleData;
            if (Utils.CheckReferenceIsNull(shipData))
                return -1;
            return shipData.m_BindKeyForward;
        }
        set
        {
            var shipData = m_ShipUIData as ShipUIMovePoleData;
            if (Utils.CheckReferenceIsNull(shipData))
                return ;
            shipData.m_BindKeyForward = value;
        }
    }
    public int bindKeyBack
    {
        get
        {
            var shipData = m_ShipUIData as ShipUIMovePoleData;
            if(Utils.CheckReferenceIsNull(shipData))
                return -1;
            return shipData.m_BindKeyBack;
        }
        set
        {
            var shipData = m_ShipUIData as ShipUIMovePoleData;
            if (Utils.CheckReferenceIsNull(shipData))
                return;
            shipData.m_BindKeyBack = value;
        }
    }
    public int bindKeyLeft      {
        get
        {
            var shipData = m_ShipUIData as ShipUIMovePoleData;
            if (Utils.CheckReferenceIsNull(shipData))
                return -1;
            return shipData.m_BindKeyLeft;
        }
        set
        {
            var shipData = m_ShipUIData as ShipUIMovePoleData;
            if (Utils.CheckReferenceIsNull(shipData))
                return;
            shipData.m_BindKeyLeft = value;
        }
    }
    public int bindKeyRight     {
        get
        {
            var shipData = m_ShipUIData as ShipUIMovePoleData;
            if (Utils.CheckReferenceIsNull(shipData))
                return -1;
            return shipData.m_BindKeyRight;
        }
        set
        {
            var shipData = m_ShipUIData as ShipUIMovePoleData;
            if (Utils.CheckReferenceIsNull(shipData))
                return;
            shipData.m_BindKeyRight = value;
        }
    }

    public Vector2 m_Direction = new Vector2();
    public GameObject m_InB;
    public GameObject m_OutB;
    public GameObject m_ArrowUp;
    public GameObject m_ArrowDown;
    public GameObject m_ArrowLeft;
    public GameObject m_ArrowRight;
    public CallbackFloat OnDistanceCallback;
    public CallbackInt OnPressCallback;
    public Callback OnDistanceMaxCallback;

    public UnityEvent forwardEvent = new UnityEvent();
    public UnityEvent backEvent = new UnityEvent();
    public UnityEvent leftEvent = new UnityEvent();
    public UnityEvent rightEvent = new UnityEvent();

    bool m_IsDown = false;
    public Align m_Align = Align.ALIGN_LEFT;
    public enum Align
    {
        ALIGN_LEFT,
        ALIGN_RIGHT,
    }
    public ShipUIMovePole()
    {
        m_Type = ShipUIType.MovePole;
        m_ShipUIData = ShipUIManager.Instance.Create((int)m_Type);
    }
    public override string GetTypeName()
    {
        return "移动杆";
    }
    public override string GetOperationName(int operation)
    {
        string name = "None";
        switch ((OperationType)operation)
        {
            case OperationType.Forward:
                name = "前进";
                break;
            case OperationType.Back:
                name = "后退";
                break;
            case OperationType.Left:
                name = "左移";
                break;
            case OperationType.Right:
                name = "右移";
                break;
        }
        return name;
    }

     
    // Update is called once per frame
    void Update()
    {
        int findID = -1;
        for (int i = 0; i < Input.touchCount; ++i)
        {
            var touch = Input.GetTouch(i);
            if (touch.position.x > Screen.width / 2 && m_Align == Align.ALIGN_RIGHT)
            {
                findID = i;
            }
            else if (touch.position.x < Screen.width / 2 && m_Align == Align.ALIGN_LEFT)
            {
                findID = i;
            }
        }


#if UNITY_ANDROID
        if (m_IsDown && findID != -1)
        {
            var touch = Input.GetTouch(findID);
            var diffent = touch.position - new Vector2(m_OutB.transform.position.x, m_OutB.transform.position.y);
#elif UNITY_STANDALONE_WIN
        if (m_IsDown)
        { 
            var diffent = Input.mousePosition - m_OutB.transform.position;
#endif
            m_Direction = diffent.normalized;
            float maxRadius = GetInBSize().x / 2;

            float currentDistance = diffent.magnitude;
            if (OnDistanceCallback != null)
                OnDistanceCallback(currentDistance);
            if (diffent.magnitude < maxRadius / 3)
            {
                if (OnPressCallback != null)
                    OnPressCallback(1);
                return;
            }
            else
            {
                if (diffent.magnitude > maxRadius)
                {
                    diffent = m_Direction * maxRadius;
                    if (OnDistanceMaxCallback != null)
                    {
                        OnDistanceMaxCallback();
                    }
                }

                m_InB.GetComponent<RectTransform>().localPosition = diffent;

                m_ArrowUp.SetActive(false);
                m_ArrowDown.SetActive(false);
                m_ArrowLeft.SetActive(false);
                m_ArrowRight.SetActive(false);
                var directionArray = GetDirection(m_Direction);
                if ((directionArray & (1 << (int)ShipUIMovePole.OperationType.Forward)) == (1 << (int)ShipUIMovePole.OperationType.Forward))
                {
                    m_ArrowUp.SetActive(true);
                    forwardEvent.Invoke();
                }
                if ((directionArray & (1 << (int)ShipUIMovePole.OperationType.Back)) == (1 << (int)ShipUIMovePole.OperationType.Back))
                {
                    m_ArrowDown.SetActive(true);
                    backEvent.Invoke();
                }
                if ((directionArray & (1 << (int)ShipUIMovePole.OperationType.Left)) == (1 << (int)ShipUIMovePole.OperationType.Left))
                {
                    m_ArrowLeft.SetActive(true);
                    leftEvent.Invoke();
                }
                if ((directionArray & (1 << (int)ShipUIMovePole.OperationType.Right)) == (1 << (int)ShipUIMovePole.OperationType.Right))
                {
                    m_ArrowRight.SetActive(true);
                    rightEvent.Invoke();
                }
            }
        }

        var shipUIData = m_ShipUIData as ShipUIMovePoleData;
        if (shipUIData.m_BindKeyForward != 0 && Input.GetKey((KeyCode)shipUIData.m_BindKeyForward))
            forwardEvent.Invoke();
        if (shipUIData.m_BindKeyBack != 0 && Input.GetKey((KeyCode)shipUIData.m_BindKeyBack))
            backEvent.Invoke();
        if (shipUIData.m_BindKeyLeft != 0 && Input.GetKey((KeyCode)shipUIData.m_BindKeyLeft))
            leftEvent.Invoke();
        if (shipUIData.m_BindKeyRight != 0 && Input.GetKey((KeyCode)shipUIData.m_BindKeyRight))
            rightEvent.Invoke();
    }

    int GetDirection(Vector3 direction)
    {
        float limitAngle = 80;//67.5f;
        direction = direction.normalized;
        var crossMut = Vector3.Cross(direction , new Vector3(0, 1, 0));
        var angle = Vector3.Dot(direction, new Vector3(0, 1, 0)) * 90;

        int ret = 0;
        if (angle > -limitAngle && angle < limitAngle && crossMut.z < 0)
             ret = ret | (1 << (int)OperationType.Left);
        if (angle > -limitAngle && angle < limitAngle && crossMut.z >= 0)
            ret = ret | (1 << (int)OperationType.Right);

        crossMut = Vector3.Cross(direction, new Vector3(1, 0, 0));
        angle = Vector3.Dot(direction, new Vector3(1, 0, 0)) * 90;
        if (angle > -limitAngle && angle < limitAngle && crossMut.z < 0)
            ret = ret | (1 << (int)OperationType.Forward);
        if (angle > -limitAngle && angle < limitAngle && crossMut.z >= 0)
            ret = ret | (1 << (int)OperationType.Back);

        return ret;
    }
    public override UnityEvent GetOperationEvent(int operationType)
    {
        UnityEvent selectedEvent = null;
        switch ((OperationType)operationType)
        {
            case OperationType.Forward:
                selectedEvent = forwardEvent;
                break;
            case OperationType.Back:
                selectedEvent = backEvent;
                break;
            case OperationType.Left:
                selectedEvent = leftEvent;
                break;
            case OperationType.Right:
                selectedEvent = rightEvent;
                break;
        }
        return selectedEvent;
    }
    public void OnInBDown(BaseEventData eventData)
    {
        var pointEventData = eventData as PointerEventData;
        m_IsDown = true;
    }
    public void OnInBUp(BaseEventData eventData)
    {
        var pointEventData = eventData as PointerEventData;
        m_InB.transform.localPosition = new Vector3();
        m_IsDown = false;

        m_ArrowUp.SetActive(true);
        m_ArrowDown.SetActive(true);
        m_ArrowLeft.SetActive(true);
        m_ArrowRight.SetActive(true);
    }

    public override void SetEditMode(bool isEditMode)
    {
        base.SetEditMode(isEditMode);
        m_OutB.GetComponent<Image>().raycastTarget = false;
        m_ArrowUp.GetComponent<Image>().raycastTarget = false;
        m_ArrowDown.GetComponent<Image>().raycastTarget = false;
        m_ArrowLeft.GetComponent<Image>().raycastTarget = false;
        m_ArrowRight.GetComponent<Image>().raycastTarget = false;
    }
    Vector2 GetInBSize()
    {
        return m_InB.GetComponent<RectTransform>().rect.size;
    }

}